package com.lmoumou.lib_pdfload.code

import java.io.*
import java.nio.ByteBuffer

/**
 * @author Lmoumou
 * @date : 2019/8/27 15:40
 */
abstract class CharacterEncoder {
    protected var pStream: PrintStream?=null

    protected abstract fun bytesPerAtom(): Int

    protected abstract fun bytesPerLine(): Int

    @Throws(IOException::class)
    protected fun encodeBufferPrefix(paramOutputStream: OutputStream) {
        this.pStream = PrintStream(paramOutputStream)
    }

    @Throws(IOException::class)
    protected fun encodeBufferSuffix(paramOutputStream: OutputStream) {
    }

    @Throws(IOException::class)
    protected fun encodeLinePrefix(paramOutputStream: OutputStream, paramInt: Int) {
    }

    @Throws(IOException::class)
    protected fun encodeLineSuffix(paramOutputStream: OutputStream) {
        this.pStream?.println()
    }

    @Throws(IOException::class)
    protected abstract fun encodeAtom(
        paramOutputStream: OutputStream,
        paramArrayOfByte: ByteArray,
        paramInt1: Int,
        paramInt2: Int
    )

    @Throws(IOException::class)
    protected fun readFully(paramInputStream: InputStream, paramArrayOfByte: ByteArray): Int {
        for (i in paramArrayOfByte.indices) {
            val j = paramInputStream.read()
            if (j == -1) {
                return i
            }
            paramArrayOfByte[i] = j.toByte()
        }
        return paramArrayOfByte.size
    }

    @Throws(IOException::class)
    fun encode(paramInputStream: InputStream, paramOutputStream: OutputStream) {
        val arrayOfByte = ByteArray(bytesPerLine())

        encodeBufferPrefix(paramOutputStream)
        while (true) {
            val j = readFully(paramInputStream, arrayOfByte)
            if (j == 0) {
                break
            }
            encodeLinePrefix(paramOutputStream, j)
            var i = 0
            while (i < j) {
                if (i + bytesPerAtom() <= j) {
                    encodeAtom(paramOutputStream, arrayOfByte, i, bytesPerAtom())
                } else {
                    encodeAtom(paramOutputStream, arrayOfByte, i, j - i)
                }
                i += bytesPerAtom()
            }
            if (j < bytesPerLine()) {
                break
            }
            encodeLineSuffix(paramOutputStream)
        }
        encodeBufferSuffix(paramOutputStream)
    }

    @Throws(IOException::class)
    fun encode(paramArrayOfByte: ByteArray, paramOutputStream: OutputStream) {
        val localByteArrayInputStream = ByteArrayInputStream(paramArrayOfByte)
        encode(localByteArrayInputStream, paramOutputStream)
    }

    fun encode(paramArrayOfByte: ByteArray): String {
        val localByteArrayOutputStream = ByteArrayOutputStream()
        val localByteArrayInputStream = ByteArrayInputStream(paramArrayOfByte)
        val str: String
        try {
            encode(localByteArrayInputStream, localByteArrayOutputStream)

            str = localByteArrayOutputStream.toString("8859_1")
        } catch (localException: Exception) {
            throw Error("CharacterEncoder.encode internal error")
        }

        return str
    }

    private fun getBytes(paramByteBuffer: ByteBuffer): ByteArray {
        var localObject: ByteArray? = null
        if (paramByteBuffer.hasArray()) {
            val arrayOfByte = paramByteBuffer.array()
            if (arrayOfByte.size == paramByteBuffer.capacity() && arrayOfByte.size == paramByteBuffer.remaining()) {
                localObject = arrayOfByte
                paramByteBuffer.position(paramByteBuffer.limit())
            }
        }
        if (localObject == null) {
            localObject = ByteArray(paramByteBuffer.remaining())


            paramByteBuffer.get((localObject as ByteArray?)!!)
        }
        return localObject
    }

    @Throws(IOException::class)
    fun encode(paramByteBuffer: ByteBuffer, paramOutputStream: OutputStream) {
        val arrayOfByte = getBytes(paramByteBuffer)
        encode(arrayOfByte, paramOutputStream)
    }

    fun encode(paramByteBuffer: ByteBuffer): String {
        val arrayOfByte = getBytes(paramByteBuffer)
        return encode(arrayOfByte)
    }

    @Throws(IOException::class)
    fun encodeBuffer(paramInputStream: InputStream, paramOutputStream: OutputStream) {
        val arrayOfByte = ByteArray(bytesPerLine())

        encodeBufferPrefix(paramOutputStream)
        while (true) {
            val j = readFully(paramInputStream, arrayOfByte)
            if (j != 0) {
                encodeLinePrefix(paramOutputStream, j)
                var i = 0
                while (i < j) {
                    if (i + bytesPerAtom() <= j) {
                        encodeAtom(paramOutputStream, arrayOfByte, i, bytesPerAtom())
                    } else {
                        encodeAtom(paramOutputStream, arrayOfByte, i, j - i)
                    }
                    i += bytesPerAtom()
                }
                encodeLineSuffix(paramOutputStream)
                if (j < bytesPerLine()) {
                    break
                }
            }
        }
        encodeBufferSuffix(paramOutputStream)
    }

    @Throws(IOException::class)
    fun encodeBuffer(paramArrayOfByte: ByteArray, paramOutputStream: OutputStream) {
        val localByteArrayInputStream = ByteArrayInputStream(paramArrayOfByte)
        encodeBuffer(localByteArrayInputStream, paramOutputStream)
    }

    fun encodeBuffer(paramArrayOfByte: ByteArray): String {
        val localByteArrayOutputStream = ByteArrayOutputStream()
        val localByteArrayInputStream = ByteArrayInputStream(paramArrayOfByte)
        try {
            encodeBuffer(localByteArrayInputStream, localByteArrayOutputStream)
        } catch (localException: Exception) {
            throw Error("CharacterEncoder.encodeBuffer internal error")
        }

        return localByteArrayOutputStream.toString()
    }

    @Throws(IOException::class)
    fun encodeBuffer(paramByteBuffer: ByteBuffer, paramOutputStream: OutputStream) {
        val arrayOfByte = getBytes(paramByteBuffer)
        encodeBuffer(arrayOfByte, paramOutputStream)
    }

    fun encodeBuffer(paramByteBuffer: ByteBuffer): String {
        val arrayOfByte = getBytes(paramByteBuffer)
        return encodeBuffer(arrayOfByte)
    }
}